package com.lifuixng.picturebackend.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lifuixng.picturebackend.common.DeleteRequest;
import com.lifuixng.picturebackend.constant.SpaceConstant;
import com.lifuixng.picturebackend.exception.BusinessException;
import com.lifuixng.picturebackend.exception.ErrorCode;
import com.lifuixng.picturebackend.exception.ThrowUtils;
import com.lifuixng.picturebackend.mapper.PictureMapper;
import com.lifuixng.picturebackend.model.dto.space.SpaceAddRequest;
import com.lifuixng.picturebackend.model.dto.space.SpaceEditRequest;
import com.lifuixng.picturebackend.model.dto.space.SpaceQueryRequest;
import com.lifuixng.picturebackend.model.dto.space.SpaceUpdateRequest;
import com.lifuixng.picturebackend.model.entity.Picture;
import com.lifuixng.picturebackend.model.entity.Space;
import com.lifuixng.picturebackend.model.entity.User;
import com.lifuixng.picturebackend.model.enums.SpaceLevelEnum;
import com.lifuixng.picturebackend.model.mapping.SpaceMapping;
import com.lifuixng.picturebackend.model.mapping.UserMapping;
import com.lifuixng.picturebackend.model.vo.space.SpaceVO;
import com.lifuixng.picturebackend.service.PictureService;
import com.lifuixng.picturebackend.service.SpaceService;
import com.lifuixng.picturebackend.mapper.SpaceMapper;
import com.lifuixng.picturebackend.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

/**
 * @author 26966
 * @description 针对表【space(空间)】的数据库操作Service实现
 * @createDate 2024-12-29 21:25:03
 */
@Service
@Slf4j
public class SpaceServiceImpl extends ServiceImpl<SpaceMapper, Space>
        implements SpaceService {

    @Resource
    private SpaceMapping spaceMapping;

    @Resource
    private UserMapping userMapping;

    @Resource
    private UserService userService;

    @Resource
    private PictureMapper pictureMapper;

    @Resource
    private TransactionTemplate transactionTemplate;

    // 使用ConcurrentHashMap存储锁对象
    private static final ConcurrentHashMap<Long, Lock> locks = new ConcurrentHashMap<>();

    /**
     * 根据空间级别 填充最大数量和容量
     *
     * @param space
     */
    @Override
    public void fillSpaceBySpaceLeve(Space space) {

        Integer spaceLevel = space.getSpaceLevel();
        SpaceLevelEnum spaceLevelEnum = SpaceLevelEnum.getEnumByValue(spaceLevel);
        ThrowUtils.throwIf(spaceLevelEnum == null, ErrorCode.PARAMS_ERROR);
        // 该空间存在枚举
        long maxSize = spaceLevelEnum.getMaxSize();
        // 空间size和count不为空，填充参数
        if (space.getMaxSize() == null) {
            space.setMaxSize(maxSize);
        }
        long maxCount = spaceLevelEnum.getMaxCount();
        if (space.getMaxCount() == null) {
            space.setMaxCount(maxCount);
        }
    }


    /**
     * 校验参数
     *
     * @param space
     * @param add
     */
    @Override
    public void verifySpace(Space space, boolean add) {
        // 校验参数
        ThrowUtils.throwIf(space == null, ErrorCode.PARAMS_ERROR);
        String spaceName = space.getSpaceName();
        Integer spaceLevel = space.getSpaceLevel();
        SpaceLevelEnum spaceLevelEnum = SpaceLevelEnum.getEnumByValue(spaceLevel);

        // 如果是添加空间
        if (add) {
            // 空间名和空间级别不能为空
            ThrowUtils.throwIf(StrUtil.isBlank(spaceName), ErrorCode.PARAMS_ERROR);
            ThrowUtils.throwIf(spaceLevel == null, ErrorCode.PARAMS_ERROR);
        }

        // 验证修改空间的数据
        if (spaceLevel != null && spaceLevelEnum == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        if (StrUtil.isNotBlank(spaceName) && spaceName.length() > 30) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "空间名称过长");
        }
    }


    /**
     * 构造查询条件
     *
     * @param spaceQueryRequest
     * @return
     */
    @Override
    public QueryWrapper<Space> getQueryWrapper(SpaceQueryRequest spaceQueryRequest) {

        QueryWrapper<Space> queryWrapper = new QueryWrapper<>();
        // 校验参数
        if (spaceQueryRequest == null) {
            return queryWrapper;
        }
        Long id = spaceQueryRequest.getId();
        Long userId = spaceQueryRequest.getUserId();
        String spaceName = spaceQueryRequest.getSpaceName();
        Integer spaceLevel = spaceQueryRequest.getSpaceLevel();
        String sortField = spaceQueryRequest.getSortField();
        String sortOrder = spaceQueryRequest.getSortOrder();

        queryWrapper.eq(ObjUtil.isNotEmpty(id), "id", id);
        queryWrapper.eq(ObjUtil.isNotEmpty(userId), "userId", userId);
        queryWrapper.like(StrUtil.isNotBlank(spaceName), "spaceName", spaceName);
        queryWrapper.eq(ObjUtil.isNotEmpty(spaceLevel), "spaceLevel", spaceLevel);
        queryWrapper.orderBy(StrUtil.isNotEmpty(sortField), sortOrder.equals("ascend"), sortField);
        return queryWrapper;
    }


    /**
     * 根据查询条件获取分页（未脱敏）
     *
     * @param spaceQueryRequest
     * @return
     */
    @Override
    public Page<Space> getSpaceByPage(SpaceQueryRequest spaceQueryRequest) {
        int current = spaceQueryRequest.getCurrent();
        int pageSize = spaceQueryRequest.getPageSize();

        return this.page(new Page<>(current, pageSize), this.getQueryWrapper(spaceQueryRequest));

    }

    @Override
    public Page<SpaceVO> getSpaceVOByPage(Page<Space> spacePage) {

        List<Space> spaceList = spacePage.getRecords();
        Page<SpaceVO> spaceVOPage = new Page<>(spacePage.getCurrent(), spacePage.getSize(), spacePage.getTotal());
        if (CollUtil.isEmpty(spaceList)) {
            return spaceVOPage;
        }
        // 对象列表 => 封装对象列表
        List<SpaceVO> spaceVOList = spaceList.stream().map(spaceMapping::spaceToSpaceVO).collect(Collectors.toList());
        // 1. 关联查询用户信息
        Set<Long> userIdSet = spaceList.stream().map(Space::getUserId).collect(Collectors.toSet());
        Map<Long, List<User>> userIdUserListMap = userService.listByIds(userIdSet).stream()
                .collect(Collectors.groupingBy(User::getId));
        // 2. 填充信息
        spaceVOList.forEach(spaceVO -> {
            Long userId = spaceVO.getUserId();
            User user = null;
            if (userIdUserListMap.containsKey(userId)) {
                user = userIdUserListMap.get(userId).get(0);
            }
            spaceVO.setUser(userMapping.userToUserVO(user));
        });
        spaceVOPage.setRecords(spaceVOList);
        return spaceVOPage;

    }

    /**
     * 更改空间 管理员才可以
     *
     * @param spaceUpdateRequest
     * @return
     */
    @Override
    public int updateSpace(SpaceUpdateRequest spaceUpdateRequest) {

        // 检验参数
        ThrowUtils.throwIf(spaceUpdateRequest == null || spaceUpdateRequest.getId() <= 0, ErrorCode.PARAMS_ERROR);
        // 转换
        Space space = spaceMapping.spaceUpdateRequestToSpace(spaceUpdateRequest);

        // 根据空间级别填充参数（数量和容量）
        this.fillSpaceBySpaceLeve(space);
        // 校验参数
        this.verifySpace(space, false);
        Space oldSpace = this.baseMapper.selectById(spaceUpdateRequest.getId());
        ThrowUtils.throwIf(oldSpace == null, ErrorCode.NOT_FOUND_ERROR);

        // 操作数据库
        space.setUpdateTime(new Date());
        int result = this.baseMapper.updateById(space);
        ThrowUtils.throwIf(result <= 0, ErrorCode.OPERATION_ERROR);

        return result;
    }

    /**
     * 删除空间
     *
     * @param deleteRequest
     * @param loginUser
     * @return
     */
    @Override
    public int deleteSpace(DeleteRequest deleteRequest, User loginUser) {
        // 检验参数
        ThrowUtils.throwIf(deleteRequest == null || deleteRequest.getId() <= 0, ErrorCode.PARAMS_ERROR);
        Space space = this.baseMapper.selectById(deleteRequest.getId());
        ThrowUtils.throwIf(space == null, ErrorCode.NOT_FOUND_ERROR);
        // 权限校验 本人和管理员
        if (!(space.getUserId().equals(loginUser.getId())) && !(userService.isAdmin(loginUser))) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
        }

        log.info("用户删除空间,空间id:{}", deleteRequest.getId());
        int result = this.baseMapper.deleteById(deleteRequest.getId());
        ThrowUtils.throwIf(result <= 0, ErrorCode.OPERATION_ERROR);
        // 删除空间下的图片
        // delete from picture where spaceId = spaceId
        log.info("用户删除空间成功,删除空间下的图片");
        QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("spaceId", space.getId());
        pictureMapper.delete(queryWrapper);
        // 可能用户空间没有照片
        // ThrowUtils.throwIf(delete <= 0, ErrorCode.OPERATION_ERROR);
        return result;
    }


    /**
     * 编辑空间 用户只能编辑空间名
     *
     * @param spaceEditRequest
     * @param loginUser
     * @return
     */
    @Override
    public int editSpace(SpaceEditRequest spaceEditRequest, User loginUser) {
        // 检验参数
        ThrowUtils.throwIf(spaceEditRequest == null || loginUser == null, ErrorCode.PARAMS_ERROR);

        // 转换
        Space space = spaceMapping.spaceEditRequestToSpace(spaceEditRequest);
        // 查看编辑的空间是否存在
        Space oldSpace = this.baseMapper.selectById(spaceEditRequest.getId());
        ThrowUtils.throwIf(oldSpace == null, ErrorCode.NOT_FOUND_ERROR);
        // 权限 空间不是本人
        if (!(oldSpace.getUserId().equals(loginUser.getId()))) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
        }
        // 操作数据库
        space.setEditTime(new Date());
        int result = this.baseMapper.updateById(space);
        ThrowUtils.throwIf(result <= 0, ErrorCode.OPERATION_ERROR);
        return result;
    }

    @Override
    public Long addSpace(SpaceAddRequest spaceAddRequest, User loginUser) {
        // 校验参数
        ThrowUtils.throwIf(spaceAddRequest == null && loginUser == null, ErrorCode.PARAMS_ERROR);

        // 转换
        Space space = spaceMapping.spaceAddRequestToSpace(spaceAddRequest);

        // 填充默认参数
        if (space.getSpaceName() == null) {
            space.setSpaceName(SpaceConstant.DEFAULT_SPACENAME);
        }
        if (space.getSpaceLevel() == null) {
            space.setSpaceLevel(SpaceConstant.DEFAULT_SPACELEVE);
        }

        // 根据空间级别填充参数
        this.fillSpaceBySpaceLeve(space);
        Long userId = loginUser.getId();
        space.setUserId(userId);
        // 校验空间
        this.verifySpace(space, true);
        // 校验空间级别权限
        // 不是管理员不可以创建非默认空间

        if (!(space.getSpaceLevel().equals(SpaceLevelEnum.COMMON.getValue())) &&
                !(userService.isAdmin(loginUser))) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "无法创建指定级别的空间");
        }
        // 用户只能创建一个空间
        // QueryWrapper<Space> spaceQueryWrapper = new QueryWrapper<>();
        // spaceQueryWrapper.eq(ObjUtil.isNotEmpty(space.getUserId()), "userId", space.getUserId());
        // int count = Math.toIntExact(this.baseMapper.selectCount(spaceQueryWrapper));
        // ThrowUtils.throwIf(count > 0, ErrorCode.PARAMS_ERROR, "已存在空间");
        //
        // // 添加空间
        // return this.baseMapper.insert(space);

        // 每个用户得到不同的锁，同一个用户得到的锁相同
        String lock = String.valueOf(userId).intern();
        synchronized (lock) {
            // 添加事务， 事务提交成功后释放锁，此时数据库有一条数据
            Long id = transactionTemplate.execute(status -> {
                // 查看是否有 空间的用户id等于登录的用户id（空间已存在）
                boolean exists = this.lambdaQuery().eq(Space::getUserId, userId).exists();
                ThrowUtils.throwIf(exists, ErrorCode.OPERATION_ERROR, "每个用户仅能只有一个私人空间");
                // 创建空间
                int result = this.baseMapper.insert(space);
                ThrowUtils.throwIf(result <= 0, ErrorCode.OPERATION_ERROR);
                return space.getId();
            });
            return id;
        }

        // 优化
        // 从ConcurrentHashMap中获取锁对象，如果不存在则创建一个新的ReentrantLock并放入map中
        // Lock lock = locks.computeIfAbsent(userId, k -> new ReentrantLock());
        // synchronized (lock) {
        //     try {
        //         // 添加事务， 事务提交成功后释放锁，此时数据库有一条数据
        //         Long id = transactionTemplate.execute(status -> {
        //             // 查看是否有 空间的用户id等于登录的用户id（空间已存在）
        //             boolean exists = this.lambdaQuery().eq(Space::getUserId, userId).exists();
        //             ThrowUtils.throwIf(exists, ErrorCode.OPERATION_ERROR, "每个用户仅能只有一个私人空间");
        //             // 创建空间
        //             int result = this.baseMapper.insert(space);
        //             ThrowUtils.throwIf(result <= 0, ErrorCode.OPERATION_ERROR);
        //             return space.getId();
        //         });
        //         //  事务提交 返回添加的id 释放锁
        //         return id;
        //     } catch (BusinessException e) {
        //         throw new BusinessException(ErrorCode.OPERATION_ERROR);
        //
        //     } finally {
        //         // // 确保在finally块中释放锁，以避免死锁
        //         // lock.unlock();
        //     }
        //
        // }
    }
}




